package master.ghrm.domain;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.joda.time.DateTime;

public class EvalSessionPlan {

	private EvaluationSession session;
	private final List<Row> rows = new ArrayList<Row>();

	public static enum SortBy {
		NAME, LAST_EVAL, EVAL_DATE
	};

	public EvaluationSession getSession() {
		return session;
	}

	public void setSession(EvaluationSession aSession) {
		this.session = aSession;
	}

	public List<Row> getRows() {
		return rows;
	}

	public void addRow(Profile profile, DateTime lastEvalDate, Evaluation evaluation, EvalSessionPlanRowState aRowState) {
		rows.add(new Row(profile, lastEvalDate, evaluation, aRowState));
	}

	public void sort(SortBy option, SortOrder sortOrder) {
		switch (option) {
		case NAME:
			nameComparator.setSortOrder(sortOrder);
			Collections.sort(rows, nameComparator);
			break;
		case LAST_EVAL:
			lastEvalComparator.setSortOrder(sortOrder);
			Collections.sort(rows, lastEvalComparator);
			break;
		case EVAL_DATE:
			evalDateComparator.setSortOrder(sortOrder);
			Collections.sort(rows, evalDateComparator);
			break;
		default:
			nameComparator.setSortOrder(sortOrder);
			Collections.sort(rows, nameComparator);
		}
	}

	public enum EvalSessionPlanRowState {

		/**
		 * User is not planned to be evaluated during this evaluation session.
		 */
		NOT_PLANNED,

		/**
		 * User is planned to be evaluated during this evaluation session. Evaluation is created, but not published yet.
		 */
		PLANNED,

		/**
		 * Evaluation for the user is published. User is not ready for the interview since not all of the assessments
		 * are done yet.
		 */
		PUBLISHED,

		/**
		 * User is ready for the interview, i.e. all of the assessments are done.
		 */
		INTERVIEW_READY,

		/**
		 * User is interviewed, but still the PDP needs to be created.
		 */
		INTERVIEWED,

		/**
		 * User is interviewed and PDP is created or PDP is not needed.
		 */
		FINISHED,

		/**
		 * Something we don't expect.
		 */
		OTHER

	}

	public enum SortOrder {

		ASCENDING, DESCENDING;

	}

	public class Row {
		private final Profile profile;
		private final DateTime lastEvalDate;
		private final Evaluation evaluation;
		private final EvalSessionPlanRowState state;

		private Row(Profile aProfile, DateTime aLastEvalDate, Evaluation anEvaluation, EvalSessionPlanRowState aState) {
			this.profile = aProfile;
			this.lastEvalDate = aLastEvalDate;
			this.evaluation = anEvaluation;
			this.state = aState;
		}

		public Profile getProfile() {
			return profile;
		}

		public DateTime getLastEvalDate() {
			return lastEvalDate;
		}

		public Evaluation getEvaluation() {
			return evaluation;
		}

		public EvalSessionPlanRowState getState() {
			return state;
		}
	}

	private interface EvalSessionPlanComparator extends Comparator<Row> {

		SortOrder getSortOrder();

		void setSortOrder(SortOrder aSortOrder);

	}

	private abstract class AbstractEvalSessionPlanComparator implements EvalSessionPlanComparator {

		private SortOrder sortOrder;

		public AbstractEvalSessionPlanComparator() {
			sortOrder = SortOrder.ASCENDING;
		}

		public SortOrder getSortOrder() {
			return sortOrder;
		}

		public void setSortOrder(SortOrder aSortOrder) {
			this.sortOrder = aSortOrder;
		}

	}

	private final EvalSessionPlanComparator nameComparator = new AbstractEvalSessionPlanComparator() {
		@Override
		public int compare(Row o1, Row o2) {
			int result = 0;
			if (o1.getProfile() != null && o2.getProfile() == null) {
				result = 1;
			} else if (o1.getProfile() == null && o2.getProfile() != null) {
				result = -1;
			} else if (o1.getProfile() != null && o2.getProfile() != null) {
				String n1 = o1.getProfile().getFullName();
				String n2 = o2.getProfile().getFullName();
				if (n1 != null && n2 == null) {
					result = 1;
				} else if (n1 == null && n2 != null) {
					result = -1;
				} else if (n1 != null && n2 != null) {
					result = n1.compareTo(n2);

					SortOrder sortOrder = getSortOrder();
					if (sortOrder != null && SortOrder.DESCENDING.equals(sortOrder)) {
						result *= -1;
					}
				}
			}

			return result;
		}
	};

	private final EvalSessionPlanComparator lastEvalComparator = new AbstractEvalSessionPlanComparator() {
		@Override
		public int compare(Row o1, Row o2) {
			int result = 0;

			if (o1.getLastEvalDate() != null && o2.getLastEvalDate() == null) {
				result = -1;
			} else if (o1.getLastEvalDate() == null && o2.getLastEvalDate() != null) {
				result = 1;
			} else if (o1.getLastEvalDate() != null && o2.getLastEvalDate() != null) {
				result = o1.getLastEvalDate().compareTo(o2.getLastEvalDate());

				SortOrder sortOrder = getSortOrder();
				if (sortOrder != null && SortOrder.DESCENDING.equals(sortOrder)) {
					result *= -1;
				}
			}

			return result;
		}
	};

	private final EvalSessionPlanComparator evalDateComparator = new AbstractEvalSessionPlanComparator() {
		@Override
		public int compare(Row o1, Row o2) {
			int result = 0;

			if (o1.getEvaluation() != null && o2.getEvaluation() == null) {
				result = -1;
			} else if (o1.getEvaluation() == null && o2.getEvaluation() != null) {
				result = 1;
			} else if (o1.getEvaluation() != null && o2.getEvaluation() != null) {
				DateTime d1 = o1.getEvaluation().getEvalDate();
				DateTime d2 = o2.getEvaluation().getEvalDate();
				if (d1 != null && d2 == null) {
					result = -1;
				} else if (d1 == null && d2 != null) {
					result = 1;
				} else if (d1 != null && d2 != null) {
					result = d1.compareTo(d2);

					SortOrder sortOrder = getSortOrder();
					if (sortOrder != null && SortOrder.DESCENDING.equals(sortOrder)) {
						result *= -1;
					}
				}
			}

			return result;
		}
	};
}
